package cn.keniykey.mc.landterritory.landflag.api;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitRunnable;

import cn.keniykey.mc.landterritory.LandTerritoryMain;
import cn.keniykey.mc.landterritory.landflag.LandFlag;

/**
 * 领地标记线程类（与Bukkit一致）
 * （请使用此类调度线程，确保标记被卸载时线程跟着关闭）
 */
public final class LandFlagScheduler {
	private LandFlagScheduler() {}
	
	private static ConcurrentHashMap<String, ConcurrentHashMap<Integer,Object>> conmap_tasks = new ConcurrentHashMap<>();
	private static final Object OBJECT = new Object();
	
	private static class LandFlagRunnable extends BukkitRunnable {
		private final String flagname1;
		private final Runnable run1;
		LandFlagRunnable(String flagname,Runnable run) {
			this.flagname1 = flagname;
			this.run1 = run;
		}
		@Override
		public void run() {
			try {
				this.run1.run();
			}catch(Exception ex) {
				ex.printStackTrace();
			}
			removeTask(this.flagname1, this.getTaskId());
		}
	}
	
	private static void removeTask(String flagname,int taskid) {
		if(!conmap_tasks.containsKey(flagname)) return;
		final ConcurrentHashMap<Integer, Object> maplist = conmap_tasks.get(flagname);
		if(maplist.isEmpty()) return;
		maplist.remove(taskid);
	}
	private static void addTask(String flagname,int taskid) {
		final ConcurrentHashMap<Integer, Object> maplist;
		if(conmap_tasks.containsKey(flagname)) {
			maplist = conmap_tasks.get(flagname);
		}else {
			maplist = new ConcurrentHashMap<>();
			conmap_tasks.put(flagname, maplist);
		}
		maplist.put(taskid, OBJECT);
	}
	public static void cancelTask() {
		if(conmap_tasks.isEmpty()) return;
		final Iterator<Entry<String, ConcurrentHashMap<Integer, Object>>> it = conmap_tasks.entrySet().iterator();
		while(it.hasNext()) {
			final ConcurrentHashMap<Integer, Object> tasks = it.next().getValue();
			final Enumeration<Integer> en_tasks = tasks.keys();
			while(it.hasNext()) {
				final int taskid = en_tasks.nextElement();
				Bukkit.getScheduler().cancelTask(taskid);
			}
			tasks.clear();
			it.remove();
		}
	}
	public static void cancelTask(LandFlag flag) {
		final String flagname = flag.getName();
		if(!conmap_tasks.containsKey(flagname)) return;
		final ConcurrentHashMap<Integer, Object> maplist = conmap_tasks.remove(flagname);
		if(maplist.isEmpty()) return;
		final Enumeration<Integer> it = maplist.keys();
		while(it.hasMoreElements()) {
			Bukkit.getScheduler().cancelTask(it.nextElement());
		}
		maplist.clear();
	}
	public static void cancelTask(LandFlagSchedulerTask task) {
		final String flagname = task.getLandFlagName();
		if(!conmap_tasks.containsKey(flagname)) return;
		final ConcurrentHashMap<Integer, Object> maplist = conmap_tasks.get(flagname);
		final int taskid = task.getTaskID();
		if(!maplist.containsKey(taskid)) return;
		Bukkit.getScheduler().cancelTask(taskid);
		maplist.remove(taskid);
	}
	
	private static void mustLoadedFlag(LandFlag flag) {
		if(!flag.isLoaded()) throw new RuntimeException("The LandFlag isnot loaded(领地标记未曾加载)");
	}
	public static int runTask(LandFlag flag,Runnable runnable) {
		mustLoadedFlag(flag);
		return Bukkit.getScheduler().runTask(LandTerritoryMain.getPlugin(), runnable).getTaskId();
	}
	public static int runTaskAsynchronously(LandFlag flag,Runnable runnable) {
		mustLoadedFlag(flag);
		return Bukkit.getScheduler().runTaskAsynchronously(LandTerritoryMain.getPlugin(), runnable).getTaskId();
	}
	public static LandFlagSchedulerTask runTaskLater(LandFlag flag,Runnable runnable,long later) {
		mustLoadedFlag(flag);
		final int taskid = new LandFlagRunnable(flag.getName(), runnable).runTaskLater(LandTerritoryMain.getPlugin(), later).getTaskId();
		if(later > 1l) addTask(flag.getName(), taskid);
		return new LandFlagSchedulerTask(flag, taskid);
	}
	public static LandFlagSchedulerTask runTaskLaterAsynchronously(LandFlag flag,Runnable runnable,long later) {
		mustLoadedFlag(flag);
		final int taskid = new LandFlagRunnable(flag.getName(), runnable).runTaskLaterAsynchronously(LandTerritoryMain.getPlugin(), later).getTaskId();
		if(later > 1l) addTask(flag.getName(), taskid);
		return new LandFlagSchedulerTask(flag, taskid);
	}
	public static LandFlagSchedulerTask runTaskTimer(LandFlag flag,Runnable runnable,long later,long again) {
		mustLoadedFlag(flag);
		final int taskid = Bukkit.getServer().getScheduler().runTaskTimer(LandTerritoryMain.getPlugin(), runnable, later, again).getTaskId();
		addTask(flag.getName(), taskid);
		return new LandFlagSchedulerTask(flag, taskid);
	}
	public static LandFlagSchedulerTask runTaskTimerAsynchronously(LandFlag flag,Runnable runnable,long later,long again) {
		mustLoadedFlag(flag);
		final int taskid = Bukkit.getServer().getScheduler().runTaskTimerAsynchronously(LandTerritoryMain.getPlugin(), runnable, later, again).getTaskId();
		addTask(flag.getName(), taskid);
		return new LandFlagSchedulerTask(flag, taskid);
	}
}